using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using AspNetMvc.Exceptions;
using AspNetMvc.Helpers;
using AspNetMvc.Services.Events.Interfaces;
using CoreVirtuoso.Config;
using CoreVirtuoso.Helpers;
using PublicDomain.ZoneInfo;
using VirtuosoDal;
using VirtuosoDal.Config;
using VirtuosoDal.Entities;
using VirtuosoDal.Repositories.RdfRepositories.Interfaces.GeoNames;
using WebGuiMvc.Helpers;
using WebGuiMvc.Helpers.Properties;

namespace AspNetMvc.Services.Events
{
    internal class EventPostParser : IEventPostParser
    {
        private readonly IGeoNamesRepository _geoNamesRepository;
        private readonly IEventDatesPostParser _eventDatesPostParser;

        public EventPostParser(IGeoNamesRepository geoNamesRepository,
           IEventDatesPostParser eventDatesPostParser)
        {
            _geoNamesRepository = geoNamesRepository;
            _eventDatesPostParser = eventDatesPostParser;
        }

        public Event Parse(FormCollection collection)
        {
            var @event = new Event();

            string title = PostValuesRetrievingHelper.GetValue(collection, "title");
            if (String.IsNullOrEmpty(title))
                throw new ValidationException("Please enter title");
            @event.Title = title;

            string description = PostValuesRetrievingHelper.GetValue(collection, "description");
            if (String.IsNullOrEmpty(description))
                throw new ValidationException("Please enter description");
            @event.Description = description;

            string cityUri = PostValuesRetrievingHelper.GetValue(collection, "cityUri");
            if (String.IsNullOrEmpty(cityUri))
                throw new ValidationException("Please choose event location");
            @event.CityUri = cityUri;

            string placeUri = PostValuesRetrievingHelper.GetValue(collection, "placeUri");
            @event.PlaceUri = placeUri;

            string timeZoneName = _geoNamesRepository.GetCityTimeZone(cityUri);
            if (String.IsNullOrEmpty(timeZoneName))
                throw new ValidationException("This region is not supported now. Please contact us for more information");

            Zone zone = Database.GetZone(timeZoneName);

            DateTimeOffset? nullableStartDateTimeOffset = _eventDatesPostParser.Parse(collection,
                                                                                      "startDate",
                                                                                      "startHours",
                                                                                      "startMinutes",
                                                                                      zone,
                                                                                      "Incorrect start date format",
                                                                                      "Incorrect start time format",
                                                                                      "Incorrect start date or time value");
            if (!nullableStartDateTimeOffset.HasValue)
                throw new ValidationException("Incorrect start date or time value");
            @event.StartDateTimeOffset = nullableStartDateTimeOffset.Value;

            @event.EndDateTimeOffset = _eventDatesPostParser.Parse(collection,
                                                                            "endDate",
                                                                            "endHours",
                                                                            "endMinutes",
                                                                            zone,
                                                                            "Incorrect end date format",
                                                                            "Incorrect end time format",
                                                                            "Incorrect end date or time value");

            if (@event.StartDateTimeOffset > @event.EndDateTimeOffset)
                throw new ValidationException("Event's start should be before end");

            var allAdditionalProperties = new List<string>();

            string typeUri = String.Format("{0}{1}", Namespaces.EventsOntologyNamespace, PostValuesRetrievingHelper.GetValue(collection, "typeSelect"));
            @event.Type = typeUri;

            List<string> additionalProperties;
            if (EventsConfigManager.TryGetAdditionalProperties(typeUri, out additionalProperties))
                allAdditionalProperties.AddRange(additionalProperties);

            var categoriesKeys = collection.Keys.OfType<string>().Where(k => k.StartsWith("categorySelect"));
            foreach (var categoryKey in categoriesKeys)
            {
                string categoryUri = String.Format("{0}{1}", Namespaces.EventsOntologyNamespace,
                    PostValuesRetrievingHelper.GetValue(collection, categoryKey));
                @event.Categories.Add(categoryUri);

                if (EventsConfigManager.TryGetAdditionalProperties(categoryUri, out additionalProperties))
                    allAdditionalProperties.AddRange(additionalProperties);
            }

            var allAdditionalPropertiesWithValues = new Dictionary<string, List<string>>();
            foreach (var additionalProperty in allAdditionalProperties)
            {
                var propertyName = additionalProperty.Split('#')[1];
                var keys = collection.Keys.OfType<string>().Where(k => k.StartsWith(propertyName));
                foreach (var key in keys)
                {
                    var value = collection[key];
                    if (!String.IsNullOrEmpty(key) && value != DummyItemsConfig.DummyItemValue)
                    {
                        if (!allAdditionalPropertiesWithValues.ContainsKey(additionalProperty))
                            allAdditionalPropertiesWithValues[additionalProperty] = new List<string>();
                        //ToDo: it works only for hierachical properties - reimplement
                        allAdditionalPropertiesWithValues[additionalProperty].Add(String.Format("{0}{1}", Namespaces.EventsOntologyNamespace, value));
                    }
                }
            }

            @event.AdditionalPropertiesWithValues = allAdditionalPropertiesWithValues;

            return @event;
        }
    }
}